// Copyright 2009 Jan Hosang <jan.hosang@gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package recipes

import (
    "container/list"
    "sort"
    
    "gb/tools"
    "gb/recipe"
)

type invocationAccumulator struct {
    invs map[*recipe.Recipe] *list.List
}

type invocationAccumulatorElement struct {
    // have to match in order for the invocations to be combined
    targets []string
    
    recp *recipe.Recipe
}

func newInvocationAcc() (ia *invocationAccumulator) {
    ia = new(invocationAccumulator)
    ia.invs = make(map[*recipe.Recipe] *list.List)
    return
}

func (ia *invocationAccumulator) Add(recp *recipe.Recipe) {
    // convert target list into slice, so it can be sorted and compared
    trgs := tools.ListToStrSlice(recp.Targets)
    sort.SortStrings(trgs)
    
    // find list of invocations of this particular recipe
    rinvs, ok := ia.invs[recp]
    if !ok {
        rinvs = list.New()
        ia.invs[recp] = rinvs
    }
    
    // iterate list to find a similar invocation i.e. producing the same target
    found := false
    for invEl := range rinvs.Iter() {
        inv := invEl.(*invocationAccumulatorElement)
        if tools.StrSlicesEqual(inv.targets, trgs) {
            found = true
            
            inv.recp.Merge(recp)
            break
        }
    }
    if !found {
        inv := &invocationAccumulatorElement{trgs, recp}
        rinvs.PushBack((interface{})(inv))
    }
}
